package com.boot2.core.utils.upload;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.DownloadFileRequest;
import com.boot2.core.HlAssert;
import com.boot2.core.SysProperties;
import com.boot2.core.conf.TencentProperties;
import com.boot2.core.conf.upload.OssProperties;
import com.boot2.core.conf.upload.QiniuProperties;
import com.boot2.core.constant.CoreConstant;
import com.boot2.core.dict.CommonEnum;
import com.boot2.core.utils.FileUtil;
import com.boot2.core.utils.StringUtils;
import com.boot2.core.web.RequestContext;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.region.Region;
import com.qiniu.common.Zone;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import lombok.SneakyThrows;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhangweilin
 * @Description: xxxxx
 * @date 2020/7/11
 */
@CommonsLog
@Component
public class FileUploadUtil extends AbstractFileUploadUtil {

    private static QiniuProperties qiniuProperties;

    private static TencentProperties tencentProperties;

    private static OssProperties ossProperties;

    private static SysProperties sysProperties;

    private static OSS oss;

    @Autowired
    public void setQiniuProperties(QiniuProperties qiniuProperties) {
        FileUploadUtil.qiniuProperties = qiniuProperties;
    }

    @Autowired
    public void setTencentProperties(TencentProperties tencentProperties) {
        FileUploadUtil.tencentProperties = tencentProperties;
    }

    @Autowired
    public void setOssProperties(OssProperties ossProperties) {
        FileUploadUtil.ossProperties = ossProperties;
    }

    @Autowired
    public void setSysProperties(SysProperties sysProperties) {
        FileUploadUtil.sysProperties = sysProperties;
    }

    @Autowired(required = false)
    public void setOss(OSS oss) {
        FileUploadUtil.oss = oss;
    }

    /**
     * 图片上传
     *
     * @param files
     * @return
     * @throws IOException
     */
    public static Map<String, List<String>> uploadImage(MultipartFile[] files, String subDir) {
        subDir = StringUtils.isEmpty(subDir) ? "upload/" : subDir;
        Object errorMessage = RequestContext.getRequest().getAttribute(CoreConstant.operationToastError);
        if (null != errorMessage) {
            HlAssert.isTrue(false, errorMessage.toString());
        }

        if (null != files) {
            log.info("上传文件个数: " + files.length);
            Map<String, List<String>> imagePathListMap = uploadFiles(files, CommonEnum.FileType.Image, subDir);
            return imagePathListMap;
        }
        HlAssert.isTrue(false, "files can not be null");
        throw new IllegalArgumentException("files can not be null");
    }

    /**
     * 图片上传，可带上参数,参数为要生成的缩略图的尺寸,如果尺寸有一个为0，则不生成缩略图
     *
     * @param files
     * @param width
     * @param height
     * @return
     * @throws IOException
     */
    public static Map<String, List<String>> uploadImage(MultipartFile[] files, int width, int height, String subDir) {
        subDir = StringUtils.isEmpty(subDir) ? "upload/" : subDir;
        Object errorMessage = RequestContext.getRequest().getAttribute(CoreConstant.operationToastError);
        if (null != errorMessage) {
            HlAssert.isTrue(false, errorMessage.toString());
        }

        Map<String, Object> map = new HashMap<>();
        if (null != files) {
            log.info("上传文件个数: " + files.length);
            // 对图片做加工处理
            Map<String, Object> imgParamMap = new HashMap<>();
            imgParamMap.put("optType", "scale");// 记录的要操作类型为缩放
            imgParamMap.put("width", width);
            imgParamMap.put("height", height);

            Map<String, List<String>> imagePathListMap = uploadFiles(files, CommonEnum.FileType.Image, imgParamMap, subDir);
            return imagePathListMap;
        }
        throw new IllegalArgumentException("files can not be null");
    }


    /**
     * 图片上传,上传到阿里云oss
     *
     * @param files
     * @return
     * @throws IOException
     */
    public static List<String> uploadFiles2Oss(MultipartFile[] files, String subDir) {
        subDir = StringUtils.isEmpty(subDir) ? "upload/" : subDir;
        Object errorMessage = RequestContext.getRequest().getAttribute(CoreConstant.operationToastError);
        if (null != errorMessage) {
            HlAssert.isTrue(false, errorMessage.toString());
        }

        Assert.isTrue(ossProperties != null && StringUtils.isNotEmpty(ossProperties.getAccessKeyId()), "oss configuration can not be null,if you want to upload file to aliyun oss,pls reg it first,and get the accessKeyId and the accessKeySecret");
        Assert.notNull(oss, "oss is null, oss configuration can not be null,if you want to upload file to aliyun oss,pls reg it first,and get the accessKeyId and the accessKeySecret");
        HlAssert.notNull(files, "files can not be null");
        log.info("oss上传文件个数: " + files.length);
        // 云账号AccessKey有所有API访问权限，建议遵循阿里云安全最佳实践，创建并使用RAM子账号进行API访问或日常运维，请登录
        // https://ram.console.aliyun.com 创建
        // 创建OSSClient实例

        String url = null;
        //文件列表
        List<String> fileList;
//        try {
        fileList = new ArrayList<>();
        for (MultipartFile file : files) {
            url = uploadFile2Oss(file, ossProperties, oss, subDir);
            fileList.add(url);
        }
//        }
        //todo 尝试下单例
//        finally {
//            // 关闭client
//            oss.shutdown();
//        }
        return fileList;
    }


    /**
     * 文件上传,上传到阿里云oss,返回原始文件名和变更后的文件名
     *
     * @param files
     * @return
     * @throws IOException
     */
    public static Map<String, String> uploadFiles2Oss2(MultipartFile[] files, String subDir) {
        subDir = StringUtils.isEmpty(subDir) ? "upload/" : subDir;
        Object errorMessage = RequestContext.getRequest().getAttribute(CoreConstant.operationToastError);
        if (null != errorMessage) {
            HlAssert.isTrue(false, errorMessage.toString());
        }

        Assert.isTrue(ossProperties != null && StringUtils.isNotEmpty(ossProperties.getAccessKeyId()), "oss configuration can not be null,if you want to upload file to aliyun oss,pls reg it first,and get the accessKeyId and the accessKeySecret");
        Assert.notNull(oss, "oss is null, oss configuration can not be null,if you want to upload file to aliyun oss,pls reg it first,and get the accessKeyId and the accessKeySecret");
        HlAssert.notNull(files, "files can not be null");
        log.info("oss上传文件个数: " + files.length);
        // 云账号AccessKey有所有API访问权限，建议遵循阿里云安全最佳实践，创建并使用RAM子账号进行API访问或日常运维，请登录
        // https://ram.console.aliyun.com 创建
        // 创建OSSClient实例

        String url = null;
        //文件列表
        Map<String, String> fileMap;
        fileMap = new LinkedHashMap<>();
        for (MultipartFile file : files) {
            url = uploadFile2Oss(file, ossProperties, oss, subDir);
            fileMap.put(url, file.getOriginalFilename());
        }
        return fileMap;
    }


    /**
     * 图片上传,上传到七牛
     *
     * @param files
     * @return
     * @throws IOException
     */
    public static List<String> uploadFiles2Qiniu(MultipartFile[] files, String subDir) {
        subDir = StringUtils.isEmpty(subDir) ? "upload/" : subDir;
        Object errorMessage = RequestContext.getRequest().getAttribute(CoreConstant.operationToastError);
        if (null != errorMessage) {
            HlAssert.isTrue(false, errorMessage.toString());
        }
        Assert.isTrue(qiniuProperties != null && StringUtils.isNotEmpty(qiniuProperties.getAccessKeyId()), "qiniu configuration can not be null,if you want to upload file to qiniu,pls reg it first,and get the accessKeyId and the accessKeySecret");
        HlAssert.notNull(files, "files can not be null");
        log.info("oss上传文件个数: " + files.length);
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(Zone.autoZone());
        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(qiniuProperties.getAccessKeyId(), qiniuProperties.getAccessKeySecret());
        String upToken = auth.uploadToken(qiniuProperties.getBucketName());
        //文件列表
        List<String> fileList = new ArrayList<>();
        for (MultipartFile file : files) {
            try {
                String realName = getRandomFileName(file);
//                System.out.println("realName = " + realName);
                com.qiniu.http.Response qresponse = uploadManager.put(file.getInputStream(), subDir + realName, upToken, null, null);
                String json = qresponse.bodyString();
//                System.out.println("qresponse = " + qresponse);
//                System.out.println("json = " + json);
                DefaultPutRet defaultPutRet = JSONObject.parseObject(json, DefaultPutRet.class);
//                System.out.println("defaultPutRet = " + defaultPutRet);
                String key = defaultPutRet.key;
//                System.out.println("key = " + key);
                fileList.add(key);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 关闭client
        return fileList;
    }

    /**
     * 图片上传,上传到腾讯云COS
     *
     * @param files
     * @return
     * @throws IOException
     */
    public static List<String> uploadFiles2TencentCos(MultipartFile[] files, String subDir) {
        subDir = StringUtils.isEmpty(subDir) ? "upload/" : subDir;
        Object errorMessage = RequestContext.getRequest().getAttribute(CoreConstant.operationToastError);
        if (null != errorMessage) {
            HlAssert.isTrue(false, errorMessage.toString());
        }
        Assert.isTrue(tencentProperties != null && StringUtils.isNotEmpty(tencentProperties.getAccessKeyId()), "cos configuration can not be null,if you want to upload file to tencent cos,pls reg it first,and get the accessKeyId and the accessKeySecret");
        HlAssert.notNull(files, "files can not be null");
        log.info("oss上传文件个数: " + files.length);

        // 1 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(tencentProperties.getAccessKeyId(), tencentProperties.getAccessKeySecret());
        // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        ClientConfig clientConfig = new ClientConfig(new Region(tencentProperties.getBucket()));
        // 3 生成cos客户端
        COSClient cosclient = new COSClient(cred, clientConfig);
        // bucket的命名规则为{name}-{appid} ，此处填写的存储桶名称必须为此格式
        String bucketName = tencentProperties.getBucketName();

        String url = null;
        //文件列表
        //文件列表
        List<String> fileList = new ArrayList<>();
        for (MultipartFile file : files) {
            url = uploadFile2TencentCos(file, tencentProperties, cosclient, subDir);
            fileList.add(url);
        }
        cosclient.shutdown();
        return fileList;
    }

    @SneakyThrows
    protected static File readFileFromOss(String key) {
        DownloadFileRequest downloadFileRequest = new DownloadFileRequest(ossProperties.getBucketName(), key);
        String dir = sysProperties.getTmpPath();
        String downloadFile = dir + File.separator + key;
        File file = new File(downloadFile);
        FileUtil.createDir(file.getParent());
        downloadFileRequest.setDownloadFile(downloadFile);
        oss.downloadFile(downloadFileRequest);
        file = new File(downloadFile);
        return file;
    }

    /**
     * 通过文件上传后，将其读为硬盘上的File对象
     *
     * @param files
     * @return
     * @throws IOException
     */
    public static File readTmpFile(MultipartFile files) throws IOException {
        String path = sysProperties.getTmpPath();
        File file = new File(path + File.separator + files.getOriginalFilename());
        files.transferTo(file);
        return file;
    }

    /**
     * 通过文件上传后，将其读为硬盘上的File对象
     * @param files
     * @param targetPath
     * @return
     * @throws IOException
     */
    public static File readTmpFile(MultipartFile files,String targetPath) throws IOException {
        File file = new File(targetPath);
        files.transferTo(file);
        return file;
    }

}
